package iq.number;

import java.math.BigDecimal;

/**
 * 浮点型测试,精度损失
 * 
 * @author Administrator
 * 
 */
public class FloatTest {

	/**
	 * @param args
	 * @author ddh
	 */
	public static void main(String[] args) {
		float a = 10.22f;
		Float b = new Float(a);
		Double c = new Double(b.doubleValue());
		System.out.println(b.floatValue() + ", " + c);

		double d = 20014999;
		long l = Double.doubleToLongBits(d);
		System.out.println(Long.toBinaryString(l));
		float f = 20014999f;
		int in = Float.floatToIntBits(f);
		System.out.println(Integer.toBinaryString(in));

		/*
		 * 　输出结果如下：
		 * 
		 * 　　Double:100000101110011000101100111100101110000000000000000000000000000
		 * 
		 * 　　Float:1001011100110001011001111001100
		 * 
		 * 　　对于输出结果分析如下。对于都不 double 的二进制左边补上符号位 0 刚好可以得到 64
		 * 位的二进制数。根据double的表示法，分为符号数、幂指数和尾数三个部分如下：
		 * 
		 * 　　0 10000010111 0011000101100111100101110000000000000000000000000000
		 * 
		 * 　　对于 float 左边补上符号位 0 刚好可以得到 32 位的二进制数。 根据float的表示法， 也分为
		 * 符号数、幂指数和尾数三个部分如下 ：
		 * 
		 * 　　0 10010111 00110001011001111001100
		 * 
		 * 　　绿色部分是符号位，红色部分是幂指数，蓝色部分是尾数。
		 * 
		 * 　　对比可以得出：
		 * 
		 * 　　符号位都是 0 。
		 * 
		 * 　　幂指数为移码表示,两者刚好也相等。
		 * 
		 * 　　唯一不同的是尾数。
		 * 
		 * 　　在 double 的尾数为： 001100010110011110010111
		 * 0000000000000000000000000000 ，省略后面的零，至少需要24位才能正确表示。
		 * 
		 * 　　而在 float 下面尾数为：00110001011001111001100，共 23 位。
		 * 
		 * 　　为什么会这样？原因很明显，因为 float 尾数 最多只能表示 23 位，所以 24 位的
		 * 001100010110011110010111 在 float 下面经过四舍五入变成了 23 位的
		 * 00110001011001111001100 。所以 20014999 在 float 下面变成了 20015000 。
		 * 
		 * 　　也就是说 20014999 虽然是在float的表示范围之内，但 在 IEEE 754 的 float 表示法精度长度没有办法表示出
		 * 20014999 ，而只能通过四舍五入得到一个近似值。
		 */
		/************************************************/
		/*
		 * Java 语言支持两种基本的浮点类型： float 和 double。java 的浮点类型都依据 IEEE 754 标准。IEEE 754
		 * 定义了32 位和 64 位双精度两种浮点二进制小数标准。
		 * 
		 * 　　IEEE 754 用科学记数法以底数为 2 的小数来表示浮点数。
		 * 
		 * 　　对于32 位浮点数float用 第1 位表示数字的符号，用第2至9位来表示指数，用 最后23 位来表示尾数，即小数部分。
		 * 
		 * 　　float(32位):
		 * 
		 * 　　对于64 位双精度浮点数，用 第1 位表示数字的符号，用 11 位表示指数，52 位表示尾数。
		 * 
		 * 　　double(64位):
		 * 
		 * 　　都是分为三个部分：
		 * 
		 * 　　（1） 一个单独的符号位s 直接编码符号s 。 　　（2）k 位的幂指数E ，移码表示 。 　　（3）n 位的小数，原码表示 。
		 * 浮点运算很少是精确的，只要是超过精度能表示的范围就会产生误差。往往产生误差不是因为数的大小，而是因为数的精度。
		 */

		System.out.println("*************************#");

		BigDecimal bg2 = new BigDecimal(2.0);
		for (int i = 0; i <= 20; i++) {
			BigDecimal bg = new BigDecimal(i * .1);
			System.out.println(bg2 + " - " + bg + " @= " + bg2.subtract(bg)
					+ "\t" + bg2.subtract(bg).doubleValue());
			System.out.println("2.0 - " + i * .1 + " = " + (2.0 - i * .1));// 与上面.double()的值相同,即double并不能完全表示准度.
		}

		System.out.println(new BigDecimal(22 / 7.0) + "\t"
				+ new BigDecimal(22.0));
		System.out.println(new BigDecimal(220 / 7.0) + "\t"
				+ new BigDecimal(220.0));
		System.out.println(new BigDecimal(2200 / 7.0) + "\t"
				+ new BigDecimal(2200.0));
		System.out.println(new BigDecimal(22000 / 7.0) + "\t"
				+ new BigDecimal(22000.0));// 最后一位都是5 ?

		System.out
				.println(new BigDecimal(
						"99999.1231111111111111111111111111111111111111111111111111111"
								+ "111111111111111111111111111111111111111111111111111111111112222222222222222222222222222"
								+ "222222222222222222222222222222222333333333333333"));// BigDecimal很长的小数位
	}

}
